var Graph = function (ctx, ctx_axis) {
    this.height = 500;
    this.width = 800;

    this.ctx = ctx;//图表层canvas对象
    this.ctx_axis = ctx_axis;//坐标轴层canvas对象

    this.axisXColor = 'black';//坐标颜色配置
    this.axisYColor = 'black';
    this.scaleXColor = 'blue';//刻度颜色配置
    this.scaleYColor = 'blue';
    this.lenAxisX = 660;//刻度像素比
    this.lenAxisY = 450;

    this.info = {//当前数据信息配置
        color:'black',
        font:'34px 黑体'
    }

    this.data = [];
    this.scaleX = 40;
    this.scaleY = 225;

    this.dataArrLen = 40;//绘制路线数组长度
    this.value = 7.5;//设置最终爆炸点

    this.lineWidth = 2;//曲线宽度

    this.lineColor = 'rgba(194,197,242,1)';//曲线颜色
    this.areaColor = 'rgba(194,197,242,.2)';//填充颜色

    this.pathBg = {//是否填充颜色
        show : true
    }

    //X轴初始刻度配置
    this.scaleXLen = {
        maxLen:2,//初始最大刻度
        pxLen:10,//单位刻度大小比例，x轴为时间刻度单位刻度大小根据动画绘制延时决定
        unit:1,//每隔几个单位显示
    }

    //Y轴初始刻度配置
    this.scaleYLen = {
        maxLen:1,//初始最大刻度
        maxY:1//Y轴含起伏，当前获取到的最大的Y轴数据，便于判断当前Y坐标轴的刻度
    }
    
    //动画延时
    this.timer = null;
    this.delay = {
        isDelay:true,
        time:100
    }
    this.percent = 3;//控制动画绘制节奏

}

Graph.prototype.init = function () {//初始化图表
    this.data = this.getDataArr()
    this.drawAxis();
    this.drawAnimation(this.ctx);
}

//绘制坐标轴
Graph.prototype.drawAxis = function () {
    this.ctx_axis.clearRect(0, 0, this.width, this.height);
    this.drawLine(this.ctx_axis, { x: 20, y: 20 }, { x: this.lenAxisX, y: 20 }, this.axisXColor);
    this.drawLine(this.ctx_axis, { x: 20, y: 20 }, { x: 20, y: this.lenAxisY }, this.axisYColor);

    //X轴刻度设置
    this.ctx_axis.beginPath();
    this.ctx_axis.fillStyle = this.scaleXColor;
    for (let i = 0; i < this.scaleXLen.maxLen/this.scaleXLen.unit; i++) {//每隔两个刻度打印一次
        this.ctx_axis.fillText(i * this.scaleXLen.unit, this.scaleX * i * this.scaleXLen.unit * this.scaleXLen.pxLen + 20, this.height - 10)
    }
    this.ctx_axis.closePath();

    //Y轴刻度设置
    this.ctx_axis.beginPath();
    this.ctx_axis.fillStyle = this.scaleYColor;
    for (let i = 1; i <= this.scaleYLen.maxLen; i++) {
        this.ctx_axis.fillText(i + 'x', 5, this.height - 20 - this.scaleY * i)
    }
    this.ctx_axis.closePath();
}

//绘制直线
Graph.prototype.drawLine = function (ctx, start, end, color) {
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.moveTo(start.x, this.height - start.y);
    ctx.lineTo(end.x, this.height - end.y);
    ctx.stroke();
    ctx.closePath()
}

//绘制文字
Graph.prototype.drawText = function({ctx,text,x='400',y='300',font=this.info.font,fontColor=this.info.color}){
    ctx.beginPath();
    ctx.font = font;
    ctx.fillStyle = fontColor;
    ctx.fillText(text,x,y);
    ctx.closePath();
}

//将数据转换为canvas像素坐标
Graph.prototype.toParseData = function(data, scaleX, scaleY) {
    let arr = [];
    for (let i = 0; i < data.length; i++) {
        arr.push({
            x:data[i].x * scaleX + 20,
            y:this.height - data[i].y * scaleY - 20
        })
    }
    return arr
}

//动画效果
Graph.prototype.drawAnimation = function (ctx) {
    this.drawAxis();
    ctx.beginPath();
    this.drawPath(ctx, this.toParseData(this.data.slice(0, this.percent), this.scaleX, this.scaleY));
    ctx.stroke();

    this.percent = this.percent + 1;
    if (this.percent > this.dataArrLen) {
        ctx.closePath()
        return
    }

    //目前数组内的x一个单位为this.scaleX个像素，一个时间刻度为10个单位(pxLen)
    if(this.data[this.percent - 1].x/this.scaleXLen.pxLen > this.scaleXLen.maxLen){
        this.scaleXLen.maxLen = this.data[this.percent - 1].x/this.scaleXLen.pxLen;
        this.scaleX = (this.lenAxisX-50) / (this.data[this.percent - 1].x)
    }
    //如果最新的y数据大于当前的最大刻度，则将最大的数据作为标准，重新生成y轴的刻度，如果后期的数据低于最大的数据，刻度不变化
    if(this.data[this.percent - 1].y > this.scaleYLen.maxY){
        this.scaleYLen.maxY = this.data[this.percent - 1].y;//存储最大值
        this.scaleYLen.maxLen = Math.ceil(this.data[this.percent - 1].y);//最大刻度
        this.scaleY = (this.lenAxisY-50) / (this.data[this.percent - 1].y + 1);//只要当前值大于最大值就更新刻度
    }

    if(this.delay.isDelay){//动画延时
        this.timer = setTimeout(()=>{
            if (this.percent > this.dataArrLen) {
                clearTimeout(this.timer)
            }
            this.drawAnimation(ctx)
        },this.delay.time)
    }else{
        window.requestAnimationFrame(this.drawAnimation.bind(this,ctx));//bind修改this指向
    }

}

//颜色填充
Graph.prototype.drawPathColor = function(ctx,point,points){
    let int = 0;
    for (let i = 0; i < points.length - 1; i++) {
        ctx.beginPath();
        if (i == 0) {
            ctx.moveTo(points[0].x, points[0].y);
            ctx.quadraticCurveTo(point[0].x, point[0].y, points[1].x, points[1].y);
            int = int + 1;
        }
        else if (i < points.length - 2) {
            ctx.moveTo(points[i].x, points[i].y);
            ctx.bezierCurveTo(point[int].x, point[int].y, point[int + 1].x, point[int + 1].y, points[i + 1].x, points[i + 1].y);
            int += 2;
        }
        else if (i == points.length - 2) {
            ctx.moveTo(points[points.length - 2].x, points[points.length - 2].y);
            ctx.quadraticCurveTo(point[point.length - 1].x, point[point.length - 1].y, points[points.length - 1].x, points[points.length - 1].y);
        }
        ctx.lineTo(points[i + 1].x, this.height - 20)
        ctx.lineTo(points[i].x, this.height - 20)
        this.drawAreaColor(ctx);
        ctx.closePath();
    }
}

// 绘制线性图表颜色填充
Graph.prototype.drawAreaColor = function(ctx,startColor, endColor) {
    var grd = ctx.createLinearGradient(0, 0, 0, 170);
    grd.addColorStop(0, this.areaColor);
    grd.addColorStop(1, this.areaColor)
    ctx.fillStyle = grd;
    ctx.fill()
}

//绘制曲线
Graph.prototype.drawGraphLine = function(ctx,point,points){
    ctx.beginPath();
    ctx.strokeStyle = this.lineColor;
    ctx.lineWidth = this.lineWidth;

    let int = 0;
    for (let i = 0; i < points.length; i++) {
        if (i == 0) {
            ctx.moveTo(points[0].x, points[0].y);
            ctx.quadraticCurveTo(point[0].x, point[0].y, points[1].x, points[1].y);
            int = int + 1;
        }
        else if (i < points.length - 2) {
            ctx.moveTo(points[i].x, points[i].y);
            ctx.bezierCurveTo(point[int].x, point[int].y, point[int + 1].x, point[int + 1].y, points[i + 1].x, points[i + 1].y);
            int += 2;
        }
        else if (i == points.length - 2) {
            ctx.moveTo(points[points.length - 2].x, points[points.length - 2].y);
            ctx.quadraticCurveTo(point[point.length - 1].x, point[point.length - 1].y, points[points.length - 1].x, points[points.length - 1].y);
        }
    }
    ctx.stroke();
    ctx.closePath();
}

//线条绘制
Graph.prototype.drawPath = function (ctx,path) {
    ctx.clearRect(0, 0, this.width, this.height);
    let point = this.getControlPoint(path);//获取控制点
    let points = path;

    this.drawGraphLine(this.ctx,point,points);//绘制曲线

    if(this.pathBg.show){
        this.drawPathColor(this.ctx,point,points);//绘制填充颜色
    }

    if (points.length > 1) {
        ctx.beginPath();
        ctx.arc(points[points.length - 1].x, points[points.length - 1].y, 5, 0, 2 * Math.PI);
        ctx.fillStyle = "rgba(194,197,242,1)";
        ctx.fill();
        ctx.closePath();

        this.drawText({
            ctx,
            text:(this.data[this.percent - 1]).y.toFixed(1)+'x'
        })
    }
}

//根据最终爆炸点推算坐标点路线
Graph.prototype.getDataArr = function(){
    let boom = this.value,arr = [];
    let len = Math.sqrt(boom*700);
    for(let i = 0; i < this.dataArrLen-1; i++){
        arr.push({
            x:len/this.dataArrLen*i,
            y:(len/this.dataArrLen*i)*(len/this.dataArrLen*i)/700
        })
    }
    arr.push({
        x:len,
        y:boom
    })
    return arr
}

//获取控制点
Graph.prototype.getControlPoint = function(path){
    let rt = 0.3,i = 0, count = path.length - 2,arr = [];
    for (; i < count; i++) {
        let a = path[i], b = path[i + 1], c = path[i + 2];
        let v1 = new Vector2(a.x - b.x, a.y - b.y);
        let v2 = new Vector2(c.x - b.x, c.y - b.y);
        let v1Len = v1.length(), v2Len = v2.length();
        let centerV = v1.normalize().add(v2.normalize()).normalize();
        let ncp1 = new Vector2(centerV.y, centerV.x * -1);
        let ncp2 = new Vector2(centerV.y * -1, centerV.x);
        if (ncp1.angle(v1) < 90) {
            let p1 = ncp1.multiply(v1Len * rt).add(b);
            let p2 = ncp2.multiply(v2Len * rt).add(b);
            arr.push(p1, p2)
        }
        else {
            let p1 = ncp1.multiply(v2Len * rt).add(b);
            let p2 = ncp2.multiply(v1Len * rt).add(b);
            arr.push(p2, p1)
        }
    }
    return arr;
}

//向量计算方法
var Vector2 = function (x, y) {
    this.x = x;
    this.y = y;
};
Vector2.prototype = {
    "length": function () {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    },
    "normalize": function () {
        var inv = 1 / this.length();
        return new Vector2(this.x * inv, this.y * inv);
    },
    "add": function (v) {
        return new Vector2(this.x + v.x, this.y + v.y);
    },
    "multiply": function (f) {
        return new Vector2(this.x * f, this.y * f);
    },
    "dot": function (v) {
        return this.x * v.x + this.y * v.y;
    },
    "angle": function (v) {
        return Math.acos(this.dot(v) / (this.length() * v.length())) * 180 / Math.PI;
    }
};

export default Graph